package com.gome.ocean.controller.gddl.app.atom;

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.Page;
import com.gome.ocean.common.utils.ResponsePage;
import com.gome.ocean.controller.gddl.app.group.GroupController;
import com.gome.ocean.dao.model.datasource.DatasourceBO;
import com.gome.ocean.dao.model.diamond.ConfigInfoBO;
import com.gome.ocean.dao.model.gddl.AppAtomBO;
import com.gome.ocean.dao.model.gddl.AppBO;
import com.gome.ocean.dao.model.gddl.AppDatasourceBO;
import com.gome.ocean.dao.model.gddl.GroupBO;
import com.gome.ocean.dao.model.gddl.GroupRuleBO;
import com.gome.ocean.service.base.AuthorityBaseController;
import com.gome.ocean.service.datax.DatasourceService;
import com.gome.ocean.service.diamond.ConfigInfoService;
import com.gome.ocean.service.gddl.AppDatasourceService;
import com.gome.ocean.service.gddl.AppService;
import com.gome.ocean.service.gddl.GddlShardAppService;
import com.gome.ocean.service.gddl.GroupRuleService;
import com.gome.ocean.service.gddl.GroupService;
import com.google.common.collect.Maps;
import com.taobao.diamond.md5.MD5;
import com.taobao.tddl.atom.common.TAtomConstants;
import com.taobao.tddl.atom.config.TAtomConfParser;
import com.taobao.tddl.atom.config.TAtomDsConfDO;
import com.taobao.tddl.atom.securety.impl.PasswordCoder;
import com.taobao.tddl.executor.common.TopologyHandler;
import com.taobao.tddl.group.jdbc.TGroupDataSource;

/**
 * @author liyuefeng
 */
@Controller
@RequestMapping(value = "/tddl/atom")
public class AtomController extends AuthorityBaseController {

    private static final Logger LOG        = LoggerFactory.getLogger(GroupController.class);
    private final static MD5    INSTANCE   = MD5.getInstance();
    private final static int    NON_BAK_ID = 0;
    private final static int    BAK_ID     = 1;

    @Autowired
    private GddlShardAppService  gddlShardAppService;
    @Autowired
    private AppService           appService;
    @Autowired
    private DatasourceService    datasourceService;
    @Autowired
    private AppDatasourceService appDatasourceService;
    @Autowired
    protected ConfigInfoService  configInfoService;
    @Autowired
    protected GroupService       groupService;
    @Autowired
    protected GroupRuleService   groupRuleService;

    @RequestMapping(value = "/toSaveAtomPage", method = RequestMethod.GET)
    public ModelAndView toSaveAtomPage(ModelAndView mav, HttpServletRequest request) {
        List<String> projectNames = null;
        try {
            if (isAdmin()) {
                projectNames = getAllProjectNames();
            } else {
                projectNames = getCurrentUserProjects(getHttpRequest());
            }
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
            mav.getModel().put("errorMsg", e.getMessage());
        }
        mav.getModel().put("projectNames", projectNames);

        mav.setViewName("gddl/atom/insert");
        return mav;
    }

    @RequestMapping(value = "/saveAtom", method = RequestMethod.POST)
    @ResponseBody
    public ResponsePage saveAtom(ResponsePage page, HttpServletRequest request, AppAtomBO appAtomBO) {
        String appName = appAtomBO.getAppName();
        AppBO appBO = appService.findAppBOByAppName(appName);
        if (appBO == null) {
            // 向diamond里通知
            boolean syncDiamondSuccess = gddlShardAppService.createAppAtom(appAtomBO);
            if (syncDiamondSuccess) {
                String projectName = appAtomBO.getProjectGroup();
                AppBO appBo = new AppBO();
                appBo.setAppName(appName);
                appBo.setProject(projectName);
                appBo.setInit(1);
                boolean saveAppData = saveAppDataSource(appAtomBO, appBo);
                if (saveAppData) {
                    return page.setSuccessMsg("建立应用数据源成功");
                } else {
                    return page.setErrorMsg("appDatasource数据插入失败");
                }
            } else {
                return page.setErrorMsg("同步diamond失败!");
            }
        } else {
            return page.setErrorMsg("appName重复");
        }
    }

    private boolean saveAppDataSource(AppAtomBO appAtomBO, AppBO appBO) {
        boolean insertAppBo = appService.insertAppBO(appBO);
        if (insertAppBo) {
            JSONObject dataSourceInfo = JSONObject.parseObject(appAtomBO.getDataSourceInfo());
            Long datasourceId = dataSourceInfo.getLong("databaseId");
            DatasourceBO datasourceBO = datasourceService.findDatasourceBOById(datasourceId);
            AppDatasourceBO appDatasourceBO = new AppDatasourceBO();
            appDatasourceBO.setAppId(appService.findAppBOByAppName(appBO.getAppName()).getId());
            appDatasourceBO.setDbName(dataSourceInfo.getString("databaseName"));
            appDatasourceBO
                .setJdbcUrl(dataSourceInfo.getString("databaseIp") + ":" + dataSourceInfo.getString("databasePort"));
            appDatasourceBO.setPassword(datasourceBO.getPassword());
            appDatasourceBO.setSourceStatus(0);
            appDatasourceBO.setSourceType(dataSourceInfo.getString("databaseType"));
            appDatasourceBO.setUserName(datasourceBO.getUserName());
            boolean insertAppDsflag = appDatasourceService.saveAppDatasourceBO(appDatasourceBO);
            if (insertAppDsflag) {
                return true;
            }
        }
        return false;
    }

    @RequestMapping(value = "/toFindAtomPage")
    public ModelAndView toFindAtomPage(ModelAndView mav, HttpServletRequest request) {
        mav.setViewName("gddl/atom/find");
        return mav;
    }

    @RequestMapping(value = "/findAppDataSourceByPage", method = RequestMethod.POST)
    @ResponseBody
    public ResponsePage findAppDataSourceByPage(ResponsePage page, HttpServletRequest request) {
        String keyWord = request.getParameter("keyWord");
        int pageNum = getPageNum();
        int pageSize = getPageSize();
        if (StringUtils.isNotBlank(keyWord)) {
            List<AppDatasourceBO> appDatasourceBOs = appDatasourceService.findAppDataSourceByDbName(keyWord);
            if (appDatasourceBOs == null && appDatasourceBOs.size() == 0) {
                page.setErrorMsg("查无结果");
            } else {
                page.setJustList(appDatasourceBOs, "查询成功");
            }
        } else {
            Page<AppDatasourceBO> appDatasourceBOs = appDatasourceService.findAllDataSource(pageNum, pageSize);
            if (appDatasourceBOs == null && appDatasourceBOs.size() == 0) {
                page.setErrorMsg("查无结果");
            } else {
                page.setPage(appDatasourceBOs, "查询成功");
            }
        }

        return page;
    }

    @RequestMapping(value = "/getDiamondList", method = RequestMethod.POST)
    @ResponseBody
    public ResponsePage getDiamondList(ResponsePage page, HttpServletRequest request, Long appdatasourceid) {
        Map<String, Object> result = new HashMap<String, Object>();
        AppDatasourceBO appDatasourceBO = appDatasourceService.findAppDatasourceBOById(appdatasourceid);
        AppBO appBO = appService.findAppBOById(appDatasourceBO.getAppId());
        if (appBO != null) {
            String dataIdGlobal = TAtomConstants.getGlobalDataId(appDatasourceBO.getDbName());
            ConfigInfoBO configInfoGlobal = configInfoService.findConfigInfoBOByDataId(dataIdGlobal);
            String dataIdApp = TAtomConstants.getAppDataId(appBO.getAppName(), appDatasourceBO.getDbName());
            ConfigInfoBO configInfoApp = configInfoService.findConfigInfoBOByDataId(dataIdApp);
            if (configInfoGlobal == null || configInfoApp == null) {
                return this.getResult(page, result, appDatasourceBO, appBO);
            } else {
                TAtomDsConfDO tConfDo = TAtomConfParser.parserTAtomDsConfDO(configInfoGlobal.getContent(), null);
                StringBuffer sb = new StringBuffer();
                String jdbcUrl = sb.append(tConfDo.getIp()).append(":").append(tConfDo.getPort()).toString();
                if (jdbcUrl.equals(appDatasourceBO.getJdbcUrl())) {
                    String dataIdPwd = TAtomConstants.getPasswdDataId(appDatasourceBO.getDbName(),
                        appDatasourceBO.getSourceType(),
                        appDatasourceBO.getUserName());
                    ConfigInfoBO configInfoPwd = configInfoService.findConfigInfoBOByDataId(dataIdPwd);

                    result.put("appDatasourcePart", appDatasourceBO);
                    result.put("appBOPart", appBO);
                    result.put("globalPart", configInfoGlobal);
                    result.put("appPart", configInfoApp);
                    result.put("pwdPart", configInfoPwd);
                    result.put("tag", 0);
                    return page.setSingleObject(result, FIND_SUCCESS);
                } else {
                    return this.getResult(page, result, appDatasourceBO, appBO);
                }
            }
        } else {
            return page.setErrorMsg("t_app内容为空");
        }
    }

    private ResponsePage getResult(ResponsePage page, Map<String, Object> result, AppDatasourceBO appDatasourceBO,
                                   AppBO appBO) {
        List<GroupBO> groupLists = groupService.findGroupBOByAppId(appDatasourceBO.getAppId());
        if (groupLists != null && groupLists.size() > 0) {
            for (GroupBO group : groupLists) {
                Map<String, Object> map = Maps.newHashMap();
                Map<String, Object> mapBak = Maps.newHashMap();
                map.put("groupId", group.getId());
                map.put("isBak", NON_BAK_ID);
                mapBak.put("groupId", group.getId());
                mapBak.put("isBak", BAK_ID);

                ConfigInfoBO globalConfig = this.JDBCUrlStr(map, group, appDatasourceBO.getJdbcUrl());
                if (globalConfig != null) {
                    String dataApp = TAtomConstants.getAppDataId(appBO.getAppName(), globalConfig.getGroupRuleName());
                    ConfigInfoBO configApp = configInfoService.findConfigInfoBOByDataId(dataApp);
                    String dataIdPwd = TAtomConstants.getPasswdDataId(appDatasourceBO.getDbName(),
                        appDatasourceBO.getSourceType(),
                        appDatasourceBO.getUserName());
                    ConfigInfoBO configInfoPwd = configInfoService.findConfigInfoBOByDataId(dataIdPwd);

                    result.put("appDatasourcePart", appDatasourceBO);
                    result.put("appBOPart", appBO);
                    result.put("globalPart", globalConfig);
                    result.put("appPart", configApp);
                    result.put("pwdPart", configInfoPwd);
                    result.put("tag", 1);
                    return page.setSingleObject(result, FIND_SUCCESS);
                }
                ConfigInfoBO globalConfigBak = this.JDBCUrlStr(mapBak, group, appDatasourceBO.getJdbcUrl());
                if (globalConfigBak != null) {
                    String dataApp = TAtomConstants.getAppDataId(appBO.getAppName(),
                        globalConfigBak.getGroupRuleName());
                    ConfigInfoBO configApp = configInfoService.findConfigInfoBOByDataId(dataApp);
                    String dataIdPwd = TAtomConstants.getPasswdDataId(appDatasourceBO.getDbName(),
                        appDatasourceBO.getSourceType(),
                        appDatasourceBO.getUserName());
                    ConfigInfoBO configInfoPwd = configInfoService.findConfigInfoBOByDataId(dataIdPwd);

                    result.put("appDatasourcePart", appDatasourceBO);
                    result.put("appBOPart", appBO);
                    result.put("globalPart", globalConfigBak);
                    result.put("appPart", configApp);
                    result.put("pwdPart", configInfoPwd);
                    result.put("tag", 1);
                    return page.setSingleObject(result, FIND_SUCCESS);
                }
            }
        }
        return page.setErrorMsg("查询错误");
    }

    private ConfigInfoBO JDBCUrlStr(Map<String, Object> map, GroupBO group, String appDSJdbcUrl) {
        List<GroupRuleBO> groupRuleBo1 = groupRuleService.getGroupRuleInfoByMap(map);
        if (groupRuleBo1 != null && groupRuleBo1.size() > 0) {
            for (GroupRuleBO rule : groupRuleBo1) {
                String globalDataId = TAtomConstants.getGlobalDataId(rule.getGroupRuleName());
                ConfigInfoBO configGlobal = configInfoService.findConfigInfoBOByDataId(globalDataId);
                TAtomDsConfDO tConfDo = TAtomConfParser.parserTAtomDsConfDO(configGlobal.getContent(), null);
                StringBuffer sb = new StringBuffer();
                String jdbcUrl = sb.append(tConfDo.getIp()).append(":").append(tConfDo.getPort()).toString();
                if (jdbcUrl.equals(appDSJdbcUrl)) {
                    configGlobal.setGroupRuleName(rule.getGroupRuleName());
                    return configGlobal;
                }
            }
        }
        return null;
    }

    @RequestMapping(value = "/getDiamondInfo", method = RequestMethod.POST)
    @ResponseBody
    public ResponsePage getDiamondInfo(ResponsePage page, HttpServletRequest request, Long appdatasourceid) {
        AppDatasourceBO appDatasourceBO = appDatasourceService.findAppDatasourceBOById(appdatasourceid);
        if (appDatasourceBO.getAppId() == 0) {
            List<ConfigInfoBO> resultList = noAppId(appDatasourceBO.getDbName());
            if (resultList.size() > 0) {
                page.setJustList(resultList, FIND_SUCCESS);
            } else {
                page.setErrorMsg(FIND_NO_RESULTS);
            }
        } else {
            List<ConfigInfoBO> resultList = hasAppId(appDatasourceBO.getAppId());
            if (resultList.size() > 0) {
                page.setJustList(resultList, FIND_SUCCESS);
            } else {
                page.setErrorMsg(FIND_NO_RESULTS);
            }
        }
        return page;
    }

    private List<ConfigInfoBO> hasAppId(Long appId) {
        List<ConfigInfoBO> configInfoBOResult = new ArrayList<ConfigInfoBO>();
        AppBO appBO = appService.findAppBOById(appId);
        String appName = appBO.getAppName();
        String APP_FORMAT_DATAID = TAtomConstants.getAppDataId(appName, "%");
        List<ConfigInfoBO> appConfigList = configInfoService.findConfigInfoBOListByDataId(APP_FORMAT_DATAID);
        if (appConfigList.size() > 0) {
            configInfoBOResult.addAll(appConfigList);
        }
        String dataIdv1 = TopologyHandler.GROUP_TOPOLOGY.format(new Object[] { appName });
        ConfigInfoBO configInfov1 = configInfoService.findConfigInfoBOByDataId(dataIdv1);
        String v1Content = configInfov1.getContent();
        String[] v1ContentSpilt = v1Content.split(",");
        for (String v1Spilt : v1ContentSpilt) {
            String dataIdGroup = TGroupDataSource.getFullDbGroupKey(v1Spilt);
            ConfigInfoBO configInfoGroup = configInfoService.findConfigInfoBOByDataId(dataIdGroup);
            configInfoBOResult.add(configInfoGroup);
        }
        return configInfoBOResult;
    }

    private List<ConfigInfoBO> noAppId(String groupRuleName) {
        List<ConfigInfoBO> configInfoBOResult = new ArrayList<ConfigInfoBO>();
        GroupRuleBO groupRuleBO = groupRuleService.findGroupRuleBOByName(groupRuleName);
        GroupBO groupBO = groupService.findGroupBOById(groupRuleBO.getGroupId());
        String groupDataId = TGroupDataSource.getFullDbGroupKey(groupBO.getGroupName());
        ConfigInfoBO configInfoGroup = configInfoService.findConfigInfoBOByDataId(groupDataId);
        configInfoBOResult.add(configInfoGroup);
        return configInfoBOResult;
    }

    @RequestMapping(value = "/showDiamondInfo", method = RequestMethod.POST)
    @ResponseBody
    public ResponsePage showDiamondInfo(ResponsePage page, HttpServletRequest request, Long configInfoId) {
        ConfigInfoBO configInfoBO = configInfoService.findConfigInfoBOById(configInfoId);
        if (configInfoBO == null) {
            page.setErrorMsg(FIND_NO_RESULTS);
        } else {
            page.setSingleObject(configInfoBO, FIND_SUCCESS);
        }
        return page;
    }

    @RequestMapping(value = "/updateDiamondInfo", method = RequestMethod.POST)
    @ResponseBody
    public ResponsePage updateDiamondInfo(ResponsePage page, HttpServletRequest request, ConfigInfoBO configInfoBO) {
        try {
            gddlShardAppService.updateDiamond(configInfoBO.getDataId(), configInfoBO.getContent());
            page.setSuccessMsg(INSERT_SUCCESS);
        } catch (Exception e) {
            LOG.error(e.getMessage());
            page.setErrorMsg(INSERT_FAILURE);
        }
        return page;
    }

    @RequestMapping(value = "/updateDiamondLists", method = RequestMethod.POST)
    @ResponseBody
    public ResponsePage updateDiamondLists(ResponsePage page, HttpServletRequest request) {

        String configInfolist = request.getParameter("configInfolist");
        String appDatasource = request.getParameter("appDatasource");
        try {
            handleConfigInfo(configInfolist);
            handleAppDataSource(appDatasource);
            page.setSuccessMsg(UPDATE_SUCCESS);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            LOG.error(e.getMessage());
            page.setErrorMsg(UPDATE_FAILURE);
        }

        return page;
    }

    private void handleAppDataSource(String appDatasource) {
        String content = JSONObject.parseObject(appDatasource).getString("appDatasource");
        String[] attrs = content.split("\n");
        AppDatasourceBO appDatasourceBO = new AppDatasourceBO();
        for (String string : attrs) {
            String key = string.split("=")[0];
            String value = string.split("=")[1];
            if ("id".equals(key)) {
                appDatasourceBO.setId(Long.valueOf(value));
                continue;
            } else if ("appId".equals(key)) {
                appDatasourceBO.setAppId(Long.valueOf(value));
                continue;
            } else if ("userName".equals(key)) {
                appDatasourceBO.setUserName(value);
                continue;
            } else if ("jdbcUrl".equals(key)) {
                appDatasourceBO.setJdbcUrl(value);
                continue;
            } else if ("sourceType".equals(key)) {
                appDatasourceBO.setSourceType(value);
                continue;
            } else if ("dbName".equals(key)) {
                appDatasourceBO.setDbName(value);
                continue;
            }
        }
        appDatasourceService.updateAppDatasourceBOById(appDatasourceBO);
    }

    private void handleConfigInfo(String configInfolist) {
        List<ConfigInfoBO> configInfoBOs = JSONArray.parseArray(configInfolist, ConfigInfoBO.class);
        for (ConfigInfoBO configInfoBO : configInfoBOs) {
            if (configInfoBO != null) {
                ConfigInfoBO oldConfigInfoBO = configInfoService.findConfigInfoBOByDataId(configInfoBO.getDataId());
                if (configInfoBO.getDataId().contains("com.taobao.tddl.atom.passwd")) {
                    if (!(configInfoBO.getContent().equals(oldConfigInfoBO.getContent()))) {
                        String password = configInfoBO.getContent().split("=")[1];
                        StringBuffer pwdContent = new StringBuffer();
                        try {
                            pwdContent.append("encPasswd=").append(new PasswordCoder().encode(password));
                        } catch (InvalidKeyException | NoSuchPaddingException | NoSuchAlgorithmException
                                | BadPaddingException | IllegalBlockSizeException e) {
                            // TODO Auto-generated catch block
                            LOG.error(e.getMessage());
                        }
                        configInfoBO.setContent(pwdContent.toString());
                        if (getMD5NewOrOld(configInfoBO, oldConfigInfoBO)) {
                            // gddlShardAppService.updateDiamond(configInfoBO.getDataId(),
                            // configInfoBO.getContent());
                        }
                    }

                } else {
                    if (getMD5NewOrOld(configInfoBO, oldConfigInfoBO)) {
                        gddlShardAppService.updateDiamond(configInfoBO.getDataId(), configInfoBO.getContent());
                    }
                }
            }
        }
    }

    public Boolean getMD5NewOrOld(ConfigInfoBO configInfoBO, ConfigInfoBO oldConfigInfoBO) {
        String newMD5 = INSTANCE.getMD5String(configInfoBO.getContent());
        String oldMD5 = oldConfigInfoBO.getMd5();
        if (newMD5.equals(oldMD5)) {
            return Boolean.FALSE;
        } else {
            return Boolean.TRUE;
        }
    }

    @RequestMapping("/deleteInvalidData")
    @ResponseBody
    public Map<String, Object> deleteInvalidData(Long appDsId) {
        Map<String, Object> map = Maps.newHashMap();
        boolean deleteSuccess = appDatasourceService.deleteAppDatasourceBOById(appDsId);
        if (deleteSuccess) {
            map.put("success", true);
        } else {
            map.put("success", false);
        }
        return map;
    }

    @RequestMapping(value = "/batchDeleteInvalidData", method = RequestMethod.POST)
    @ResponseBody
    public Map<String, Object> batchDeleteInvalidData(HttpServletRequest request, Long a) {
        Map<String, Object> map = Maps.newHashMap();
        int i = 0;
        List<AppDatasourceBO> appDsLists = appDatasourceService.findAllDataSource();
        if (appDsLists != null && appDsLists.size() > 0) {
            for (AppDatasourceBO appDs : appDsLists) {
                String dataIdGlobal = TAtomConstants.getGlobalDataId(appDs.getDbName());
                ConfigInfoBO configInfoGlobal = configInfoService.findConfigInfoBOByDataId(dataIdGlobal);
                AppBO appBO = appService.findAppBOById(appDs.getAppId());
                if (appBO != null) {
                    String dataIdApp = TAtomConstants.getAppDataId(appBO.getAppName(), appDs.getDbName());
                    ConfigInfoBO configInfoApp = configInfoService.findConfigInfoBOByDataId(dataIdApp);
                    if (configInfoGlobal == null || configInfoApp == null) {
                        boolean deleteSuccess = appDatasourceService.deleteAppDatasourceBOById(appDs.getId());
                        i++;
                    }
                } else {
                    boolean deleteSuccess = appDatasourceService.deleteAppDatasourceBOById(appDs.getId());
                    i++;
                }
            }
            map.put("success", true);
            map.put("msg", "共物理删除符合条件的无效数据为：" + i + "条");
        } else {
            map.put("success", false);
        }
        return map;
    }

}
